#include "stdafx.h"
#include "File.h"


sClassAttributes::sClassAttributes()
{
	Version = -1;
	ClassName = ATL::CString("");
}

sClassAttributes::sClassAttributes( const sClassAttributes& attribute )
{
	Version = attribute.Version;
	ClassName = attribute.ClassName;
}

sClassAttributes::sClassAttributes( const long vers, const ATL::CString cname )
{
	Version = vers;
	ClassName = cname;
}

int sClassAttributes::CompareWith( const sClassAttributes& attribute )
{
	if(ClassName.Compare(attribute.ClassName) != 0)
		return ATTR_DIFFERENT_CLASSES;

	if (Version < attribute.Version)
		return ATTR_SMALLER;
	else
		if (Version == attribute.Version)
			return ATTR_EQUAL;
		else
			return ATTR_GREATER;
}

CException::CException( const int nErrCode, ATL::CString strErrMess )
{
	m_strErrMess.Format(_T("%s[%d]: %s"), errorCodeAsString(nErrCode),	nErrCode, strErrMess);
	m_iErrCode = nErrCode;
}

CException::CException( const CException& e ) :
							m_iErrCode(e.m_iErrCode)
{
	m_strErrMess = e.m_strErrMess;
}

const ATL::CString CException::errorCodeAsString(int nErrCode)
{
	switch (nErrCode)
	{
		case PREPRCS_OK          : return ATL::CString("PREPRCS_OK");
		case PREPRCS_ERROR       : return ATL::CString("PREPRCS_ERROR");
		case PREPRCS_INTERNAL    : return ATL::CString("PREPRCS_INTERNAL");
		case PREPRCS_PERM        : return ATL::CString("PREPRCS_PERM");
		case PREPRCS_ABORT       : return ATL::CString("PREPRCS_ABORT");
		case PREPRCS_BUSY        : return ATL::CString("PREPRCS_BUSY");
		case PREPRCS_LOCKED      : return ATL::CString("PREPRCS_LOCKED");
		case PREPRCS_NOMEM       : return ATL::CString("PREPRCS_NOMEM");
		case PREPRCS_READONLY    : return ATL::CString("PREPRCS_READONLY");
		case PREPRCS_INTERRUPT   : return ATL::CString("PREPRCS_INTERRUPT");
		case PREPRCS_IOERR       : return ATL::CString("PREPRCS_IOERR");
		case PREPRCS_CORRUPT     : return ATL::CString("PREPRCS_CORRUPT");
		case PREPRCS_NOTFOUND    : return ATL::CString("PREPRCS_NOTFOUND");
		case PREPRCS_FULL        : return ATL::CString("PREPRCS_FULL");
		case PREPRCS_CANTOPEN    : return ATL::CString("PREPRCS_CANTOPEN");
		case PREPRCS_EMPTY       : return ATL::CString("PREPRCS_EMPTY");
		case PREPRCS_MISMATCH    : return ATL::CString("PREPRCS_MISMATCH");
		case PREPRCS_MISUSE      : return ATL::CString("PREPRCS_MISUSE");
		case PREPRCS_FORMAT      : return ATL::CString("PREPRCS_FORMAT");
		case PREPRCS_RANGE       : return ATL::CString("PREPRCS_RANGE");
		case PREPRCS_ROW         : return ATL::CString("PREPRCS_ROW");
		case PREPRCS_COLUMN      : return ATL::CString("PREPRCS_COLUMN");
		case PREPRCS_DONE        : return ATL::CString("PREPRCS_DONE");
		default: return ATL::CString("UNKNOWN_ERROR");
	}
}

const int CException::errorCode()
{
	return m_iErrCode;
}

const ATL::CString CException::errorMessage()
{
	return m_strErrMess;
}

CFile::CFile()
{
}

CFile::~CFile()
{
	try
	{
		if(m_stmFile)
			m_stmFile.close();
	}
	catch(CException &e)
	{
		//print Error
 		//::MessageBoxW(NULL, e.errorMessage(), L"Deleting CFile object error", MB_OK|MB_ICONERROR);
		throw(e);
	}
}

bool CFile::OpenFile( ATL::CString FilePath, int Access, bool BinariMode)
{
	try
	{
		m_bIsAttrSpecified = false;
		std::ios_base::open_mode mode;
		switch(Access)
		{
		case AM_APPEND:
			if (BinariMode)
				mode = std::ios::in | std::ios::out | std::ios::binary;
			else
				mode = std::ios::in | std::ios::out;
			break;
		case AM_READ:
			if (BinariMode)
				mode = std::ios::in | std::ios::binary;
			else
				mode = std::ios::in;
			break;
		case AM_WRITE:
			if (BinariMode)
				mode = std::ios::out | std::ios::binary;
			else
				mode = std::ios::out;
			break;
		default:
			throw CException(PREPRCS_IOERR, ATL::CString("Access method not allowed"));

		}
		m_bBinary = BinariMode;

		new(&m_stmFile) std::fstream;
		m_stmFile.open(FilePath, mode);
		if (m_stmFile.is_open())
		{
// 			if (Access == AM_APPEND || Access == AM_READ)
// 			{
// 				ReadAttributes(m_attrFile);
// 			}
			return true;
		}
		else
			return false;
// 			throw CException(PREPRCS_IOERR, ATL::CString("Couldn't open file"));
	}
	catch(CException &e)
	{
		//print Error
 		//::MessageBoxW(NULL, e.errorMessage(), L"Opening file error", MB_OK|MB_ICONERROR);
		throw(e);
		return false;
	}
}

void CFile::CloseFile()
{
	try
	{
		if(m_stmFile)
			m_stmFile.close();
	}
	catch(CException &e)
	{
		//print Error
 		//::MessageBoxW(NULL, e.errorMessage(), L"Closing file error", MB_OK|MB_ICONERROR);
		throw(e);
	}
}

bool CFile::WriteAttributes( const sClassAttributes attribute )
{
	try
	{
		if (!m_stmFile)
			throw CException(PREPRCS_EMPTY, ATL::CString("File doesn't specified"));
		if (m_bIsAttrSpecified)
			throw CException(PREPRCS_LOCKED, ATL::CString("The file already have the attribute"));
		USES_CONVERSION;
		if(m_bBinary)
		{
			m_stmFile.seekp(std::ios::beg, 0);

			char szNil;
			m_stmFile.write((char *)PREPRCS_ATTR_BEG, strlen(PREPRCS_ATTR_BEG));
			szNil = '\n';
			m_stmFile.write((char *)&szNil, sizeof(char));

			m_stmFile.write((char *)CT2A(attribute.ClassName), attribute.ClassName.GetLength());
			if(m_stmFile.fail())
				throw CException(PREPRCS_IOERR, ATL::CString("Could not write attribute to the file"));

			szNil = '\t';
			m_stmFile.write((char *)&szNil, sizeof(char));
			if(m_stmFile.fail())
				throw CException(PREPRCS_IOERR, ATL::CString("Could not write attribute to the file"));

			m_stmFile.write((char *) &attribute.Version, sizeof(long));
			if(m_stmFile.fail())
				throw CException(PREPRCS_IOERR, ATL::CString("Could not write attribute to the file"));

			m_stmFile.write((char *)PREPRCS_ATTR_END, strlen(PREPRCS_ATTR_END));
			szNil = '\n';
			m_stmFile.write((char *)&szNil, sizeof(char));
		}
		else
		{
			m_stmFile.seekp(std::ios::beg, 0);


			m_stmFile << PREPRCS_ATTR_BEG << "\n";
				if(m_stmFile.fail())
					throw CException(PREPRCS_IOERR, ATL::CString("Could not write attribute to the file"));

			m_stmFile << CT2A(attribute.ClassName);
			if(m_stmFile.fail())
				throw CException(PREPRCS_IOERR, ATL::CString("Could not write attribute to the file"));

			m_stmFile << "\t" << attribute.Version << "\n";
			if(m_stmFile.fail())
				throw CException(PREPRCS_IOERR, ATL::CString("Could not write attribute to the file"));

			m_stmFile << PREPRCS_ATTR_END << "\n";
				if(m_stmFile.fail())
					throw CException(PREPRCS_IOERR, ATL::CString("Could not write attribute to the file"));
		}
		m_bIsAttrSpecified = true;
		return true;
	}
	catch(CException &e)
	{
		//print Error
		//::MessageBoxW(NULL, e.errorMessage(), L"Writing file attribute error", MB_OK|MB_ICONERROR);
		throw(e);
		return false;
	}
}

bool CFile::ReadAttributes( sClassAttributes& attribute )
{
	try
	{
		if (!m_stmFile)
			throw CException(PREPRCS_EMPTY, ATL::CString("File doesn't specified"));
		if(m_bBinary)
		{
			m_stmFile.seekg(std::ios::beg, 0);

			char buff[ATTR_MEM_SIZE];
			m_stmFile.getline(buff, ATTR_MEM_SIZE, '\n');
			if (strcmp(buff, PREPRCS_ATTR_BEG) != 0)
			{
				m_stmFile.seekg(std::ios::beg, 0);
				throw CException(PREPRCS_IOERR, ATL::CString("File doesn't contain attribute"));
			}

			m_stmFile.getline(buff, ATTR_MEM_SIZE, '\t');
			attribute.ClassName = ATL::CString(buff);

			m_stmFile.read((char *) &attribute.Version, sizeof(long));

			if(m_stmFile.fail())
				throw CException(PREPRCS_IOERR, ATL::CString("Could not read attribute from the file"));

			m_stmFile.getline(buff, ATTR_MEM_SIZE, '\n');
			if (strcmp(buff, PREPRCS_ATTR_END) != 0)
			{
				throw CException(PREPRCS_IOERR, ATL::CString("Bad attribute format"));
			}
		}
		else
		{
			m_stmFile.seekg(std::ios::beg, 0);

			char buff[ATTR_MEM_SIZE];
			m_stmFile.getline(buff, ATTR_MEM_SIZE, '\n');
			if (strcmp(buff, PREPRCS_ATTR_BEG) != 0)
			{
				m_stmFile.seekg(std::ios::beg, 0);
				throw CException(PREPRCS_IOERR, ATL::CString("File doesn't contain attribute"));
			}

			m_stmFile.getline(buff, ATTR_MEM_SIZE, '\t');
			attribute.ClassName = ATL::CString(buff);

			if(m_stmFile.fail())
				throw CException(PREPRCS_IOERR, ATL::CString("Could not read attribute from the file"));
			
			m_stmFile >> attribute.Version;

			if(m_stmFile.fail())
				throw CException(PREPRCS_IOERR, ATL::CString("Could not read attribute from the file"));

			m_stmFile.get();
			m_stmFile.getline(buff, ATTR_MEM_SIZE, '\n');
			if (strcmp(buff, PREPRCS_ATTR_END) != 0)
			{
				throw CException(PREPRCS_IOERR, ATL::CString("Bad attribute format"));
			}
		}
		m_bIsAttrSpecified = true;
		return true;
	}
	catch(CException &e)
	{
		//print Error
 		//::MessageBoxW(NULL, e.errorMessage(), L"Reading file attribute error", MB_OK|MB_ICONERROR);
		throw(e);
		return false;
	}
}

bool CFile::operator>>( long &integer )
{
	try
	{
		if (!m_stmFile)
			throw CException(PREPRCS_EMPTY, ATL::CString("File doesn't specified"));
		if(m_bBinary)
		{
			m_stmFile.read((char *) &integer, sizeof(long));
			
			if(m_stmFile.fail())
				throw CException(PREPRCS_IOERR, ATL::CString("Could not read integer from the file"));
		}
		else
		{
			m_stmFile >> integer;
			
			if(m_stmFile.fail())
				throw CException(PREPRCS_IOERR, ATL::CString("Could not read integer from the file"));
		}
		return true;
	}
	catch(CException &e)
	{
		//print Error
 		//::MessageBoxW(NULL, e.errorMessage(), L"Reading integer error", MB_OK|MB_ICONERROR);
		throw(e);
		return false;
	}
}

bool CFile::operator>>( double &natural )
{
	try
	{
		if (!m_stmFile)
			throw CException(PREPRCS_EMPTY, ATL::CString("File doesn't specified"));
		if(m_bBinary)
		{
			m_stmFile.read((char *) &natural, sizeof(double));
			
			if(m_stmFile.fail())
				throw CException(PREPRCS_IOERR, ATL::CString("Could not read double from the file"));
		}
		else
		{
			m_stmFile >> natural;
			
			if(m_stmFile.fail())
				throw CException(PREPRCS_IOERR, ATL::CString("Could not read double from the file"));
		}
		return true;
	}
	catch(CException &e)
	{
		//print Error
 		//::MessageBoxW(NULL, e.errorMessage(), L"Reading double error", MB_OK|MB_ICONERROR);
		throw(e);
		return false;
	}
}

bool CFile::operator>>( sRealPoint &point )
{
	try
	{
		if (!m_stmFile)
			throw CException(PREPRCS_EMPTY, ATL::CString("File doesn't specified"));
		if(m_bBinary)
		{
			m_stmFile.read((char *) &point.x, sizeof(double));

			if(m_stmFile.fail())
				throw CException(PREPRCS_IOERR, ATL::CString("Could not read sRealPoint from the file"));

			m_stmFile.read((char *) &point.y, sizeof(double));

			if(m_stmFile.fail())
				throw CException(PREPRCS_IOERR, ATL::CString("Could not read sRealPoint from the file"));
		}
		else
		{
			m_stmFile >> point.x;

			if(m_stmFile.fail())
				throw CException(PREPRCS_IOERR, ATL::CString("Could not read sRealPoint from the file"));

			m_stmFile >> point.y;

			if(m_stmFile.fail())
				throw CException(PREPRCS_IOERR, ATL::CString("Could not read sRealPoint from the file"));
		}
		return true;
	}
	catch(CException &e)
	{
		//print Error
 		//::MessageBoxW(NULL, e.errorMessage(), L"Reading sRealPoint error", MB_OK|MB_ICONERROR);
		throw(e);
		return false;
	}
}

bool CFile::operator>>( sIntPoint &point )
{
	try
	{
		if (!m_stmFile)
			throw CException(PREPRCS_EMPTY, ATL::CString("File doesn't specified"));
		if(m_bBinary)
		{
			m_stmFile.read((char *) &point.x, sizeof(int));

			if(m_stmFile.fail())
				throw CException(PREPRCS_IOERR, ATL::CString("Could not read sIntPoint from the file"));

			m_stmFile.read((char *) &point.y, sizeof(int));

			if(m_stmFile.fail())
				throw CException(PREPRCS_IOERR, ATL::CString("Could not read sIntPoint from the file"));
		}
		else
		{
			m_stmFile >> point.x;

			if(m_stmFile.fail())
				throw CException(PREPRCS_IOERR, ATL::CString("Could not read sIntPoint from the file"));

			m_stmFile >> point.y;

			if(m_stmFile.fail())
				throw CException(PREPRCS_IOERR, ATL::CString("Could not read sIntPoint from the file"));
		}
		return true;
	}
	catch(CException &e)
	{
		//print Error
 		//::MessageBoxW(NULL, e.errorMessage(), L"Reading sIntPoint error", MB_OK|MB_ICONERROR);
		throw(e);
		return false;
	}
}

bool CFile::operator>>( ATL::CString &str )
{
	try
	{
		if (!m_stmFile)
			throw CException(PREPRCS_EMPTY, ATL::CString("File doesn't specified"));
		if(m_bBinary)
		{
			char buff[ATTR_MEM_SIZE];
			m_stmFile.getline(buff, ATTR_MEM_SIZE, '\n');
			if(m_stmFile.fail())
				throw CException(PREPRCS_IOERR, ATL::CString("Could not CString attribute from the file"));

			str = ATL::CString(buff);
		}
		else
		{
			char buff[ATTR_MEM_SIZE];
			m_stmFile.getline(buff, ATTR_MEM_SIZE, '\n');
			if(m_stmFile.fail())
				throw CException(PREPRCS_IOERR, ATL::CString("Could not CString attribute from the file"));

			str = ATL::CString(buff);
		}

		return true;
	}
	catch(CException &e)
	{
		//print Error
 		//::MessageBoxW(NULL, e.errorMessage(), L"Reading CString error", MB_OK|MB_ICONERROR);
		throw(e);
		return false;
	}
}

bool CFile::operator<<( const long integer )
{
	try
	{
		if (!m_stmFile)
			throw CException(PREPRCS_EMPTY, ATL::CString("File doesn't specified"));
		if(m_bBinary)
		{
			m_stmFile.write((char *) &integer, sizeof(long));

			if(m_stmFile.fail())
				throw CException(PREPRCS_IOERR, ATL::CString("Could not write integer to the file"));
		}
		else
		{
			m_stmFile << integer << " ";
			
			if(m_stmFile.fail())
				throw CException(PREPRCS_IOERR, ATL::CString("Could not write integer to the file"));
		}
		return true;
	}
	catch(CException &e)
	{
		//print Error
 		//::MessageBoxW(NULL, e.errorMessage(), L"Writing integer error", MB_OK|MB_ICONERROR);
		throw(e);
		return false;
	}
}

bool CFile::operator<<( const double natural )
{
	try
	{
		if (!m_stmFile)
			throw CException(PREPRCS_EMPTY, ATL::CString("File doesn't specified"));
		if(m_bBinary)
		{
			m_stmFile.write((char *) &natural, sizeof(double));
			
			if(m_stmFile.fail())
				throw CException(PREPRCS_IOERR, ATL::CString("Could not write double to the file"));
		}
		else
		{
			m_stmFile << natural << " ";
			
			if(m_stmFile.fail())
				throw CException(PREPRCS_IOERR, ATL::CString("Could not write double to the file"));
		}
		return true;
	}
	catch(CException &e)
	{
		//print Error
 		//::MessageBoxW(NULL, e.errorMessage(), L"Writing double error", MB_OK|MB_ICONERROR);
		throw(e);
		return false;
	}
}

bool CFile::operator<<( const sRealPoint point )
{
	try
	{
		if (!m_stmFile)
			throw CException(PREPRCS_EMPTY, ATL::CString("File doesn't specified"));
		if(m_bBinary)
		{
			m_stmFile.write((char *) &point.x, sizeof(double));

			if(m_stmFile.fail())
				throw CException(PREPRCS_IOERR, ATL::CString("Could not write sRealPoint to the file"));

			m_stmFile.write((char *) &point.y, sizeof(double));

			if(m_stmFile.fail())
				throw CException(PREPRCS_IOERR, ATL::CString("Could not write sRealPoint to the file"));
		}
		else
		{
			m_stmFile << point.x << " ";

			if(m_stmFile.fail())
				throw CException(PREPRCS_IOERR, ATL::CString("Could not write sRealPoint to the file"));

			m_stmFile << point.y << " ";

			if(m_stmFile.fail())
				throw CException(PREPRCS_IOERR, ATL::CString("Could not write sRealPoint to the file"));
		}
		return true;
	}
	catch(CException &e)
	{
		//print Error
 		//::MessageBoxW(NULL, e.errorMessage(), L"Writing sRealPoint error", MB_OK|MB_ICONERROR);
		throw(e);
		return false;
	}
}

bool CFile::operator<<( const sIntPoint point )
{
	try
	{
		if (!m_stmFile)
			throw CException(PREPRCS_EMPTY, ATL::CString("File doesn't specified"));
		if(m_bBinary)
		{
			m_stmFile.write((char *)&point.x, sizeof(int));

			if(m_stmFile.fail())
				throw CException(PREPRCS_IOERR, ATL::CString("Could not write sIntPoint to the file"));

			m_stmFile.write((char *)&point.y, sizeof(int));

			if(m_stmFile.fail())
				throw CException(PREPRCS_IOERR, ATL::CString("Could not write sIntPoint to the file"));
		}
		else
		{
			m_stmFile << point.x << " ";

			if(m_stmFile.fail())
				throw CException(PREPRCS_IOERR, ATL::CString("Could not write sIntPoint to the file"));

			m_stmFile << point.y << " ";

			if(m_stmFile.fail())
				throw CException(PREPRCS_IOERR, ATL::CString("Could not write sIntPoint to the file"));
		}
		return true;
	}
	catch(CException &e)
	{
		//print Error
 		//::MessageBoxW(NULL, e.errorMessage(), L"Writing sIntPoint error", MB_OK|MB_ICONERROR);
		throw(e);
		return false;
	}
}

bool CFile::operator<<( const ATL::CString str )
{
	try
	{
		if (!m_stmFile)
			throw CException(PREPRCS_EMPTY, ATL::CString("File doesn't specified"));
		USES_CONVERSION;
		if(m_bBinary)
		{

			m_stmFile.write((char *)CT2A(str), str.GetLength());
			if(m_stmFile.fail())
				throw CException(PREPRCS_IOERR, ATL::CString("Could not write CString to the file"));

			char szNil = '\n';
			m_stmFile.write((char *)&szNil, sizeof(char));
			if(m_stmFile.fail())
				throw CException(PREPRCS_IOERR, ATL::CString("Could not write CString to the file"));
		}
		else
		{
			m_stmFile << CT2A(str) << "\n";
			if(m_stmFile.fail())
				throw CException(PREPRCS_IOERR, ATL::CString("Could not write CString to the file"));
		}
		return true;
	}
	catch(CException &e)
	{
		//print Error
 		//::MessageBoxW(NULL, e.errorMessage(), L"Writing CString error", MB_OK|MB_ICONERROR);
		throw(e);
		return false;
	}
}

bool CFile::Endl()
{
	try
	{
		if (!m_stmFile)
			throw CException(PREPRCS_EMPTY, ATL::CString("File doesn't specified"));
		if(m_bBinary)
		{
			throw CException(PREPRCS_EMPTY, ATL::CString("Binary mode doesn't allow Endl function"));
		}
		else
		{
			m_stmFile << std::endl;
		}
		return true;
	}
	catch(CException &e)
	{
		//print Error
 		//::MessageBoxW(NULL, e.errorMessage(), L"Writing CString error", MB_OK|MB_ICONERROR);
		throw(e);
		return false;
	}
}